package com.jvtd.rong_im;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;

import com.jvtd.rong_im.listener.BaseConnectionStatusListener;
import com.jvtd.rong_im.listener.BaseConversationClickListener;
import com.jvtd.rong_im.listener.BaseConversationListBehaviorListener;
import com.jvtd.rong_im.listener.BaseReceiveMessageListener;
import com.jvtd.rong_im.listener.BaseSendMessageListener;
import com.jvtd.rong_im.mInterface.RongIMConnectCallback;
import com.jvtd.rong_im.mInterface.RongIMGroupInfoProviderCallback;
import com.jvtd.rong_im.mInterface.RongIMGroupUserInfoProviderCallback;
import com.jvtd.rong_im.mInterface.RongIMUserInfoProviderCallback;
import com.jvtd.rong_im.module.BaseExtensionModule;
import com.jvtd.rong_im.provider.BaseRongIMMessageItemProvider;
import com.jvtd.rong_im.utils.ProcessUtil;

import java.util.List;
import java.util.Map;

import io.rong.imkit.DefaultExtensionModule;
import io.rong.imkit.IExtensionModule;
import io.rong.imkit.RongExtensionManager;
import io.rong.imkit.RongIM;
import io.rong.imkit.manager.IUnReadMessageObserver;
import io.rong.imkit.model.GroupUserInfo;
import io.rong.imkit.widget.provider.IContainerItemProvider;
import io.rong.imlib.RongIMClient;
import io.rong.imlib.model.CSCustomServiceInfo;
import io.rong.imlib.model.Conversation;
import io.rong.imlib.model.Group;
import io.rong.imlib.model.Message;
import io.rong.imlib.model.MessageContent;
import io.rong.imlib.model.PublicServiceProfile;
import io.rong.imlib.model.PublicServiceProfileList;
import io.rong.imlib.model.UserInfo;
import io.rong.push.RongPushClient;
import io.rong.push.common.RongException;

/*
 * Create by Jack Zhang
 */
public class JvtdRongIM
{
  private static final String TAG = "JvtdRongIM";

  @SuppressLint("StaticFieldLeak")
  private static volatile JvtdRongIM instance;
  private Context mContext;

  private JvtdRongIM(Context context)
  {
    this.mContext = context;
  }

  public static JvtdRongIM getInstance(Context context)
  {
    if (instance == null)
      synchronized (JvtdRongIM.class)
      {
        if (instance == null)
          instance = new JvtdRongIM(context.getApplicationContext());
      }
    return instance;
  }

  //-----------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  连接功能  ------------------------------------------------------
  //-----------------------------------------------------------------------------------------------------------------------

  /**
   * 初始化
   *
   * @param appKey 融云Key
   */
  public JvtdRongIM init(String appKey)
  {
    if (ProcessUtil.isMainProcess(mContext))
      RongIM.init(mContext, appKey);
    else
      Log.e(TAG, "init() error");
    return this;
  }

  /**
   * <p>连接服务器，在整个应用程序全局，只需要调用一次，需在 {@link #init(String)} 之后调用。</p>
   * <p>如果调用此接口遇到连接失败，SDK 会自动启动重连机制进行最多10次重连，分别是1, 2, 4, 8, 16, 32, 64, 128, 256, 512秒后。
   * 在这之后如果仍没有连接成功，还会在当检测到设备网络状态变化时再次进行重连。</p>
   * <p>
   * 注意
   * 1. connect 方法只需要在 App 启动后调用一次即可，后续如果网络抖动，SDK 都会做自动重连；
   * 2. 在特殊机型上，App 在后台时间过长后，会被冻结，当再次启动后，SDK 无法检测到网络变化，
   * 此时的补偿链接方法是，在你的 MainActivity 界面的 onResume 方法中判断网络状态是否 unavailable，然后再做一次 connect() 调用
   *
   * @param token    从服务端获取的用户身份令牌（Token）。
   * @param callback 连接回调。
   * @Override public void onResume()
   * {
   * super.onResume();
   * if (IMTask.IMKitApi.getCurrentConnectionStatus().equals(RongIMClient.ConnectionStatusListener.ConnectionStatus.NETWORK_UNAVAILABLE))
   * {
   * RongIM.connect(token, null);
   * }
   * }
   */
  public void connect(String token, RongIMConnectCallback callback)
  {
    if (ProcessUtil.isMainProcess(mContext))
    {
      RongIM.connect(token, new RongIMClient.ConnectCallback()
      {
        /**
         * Token 错误。可以从下面两点检查
         * 1.Token 是否过期，如果过期您需要向 App Server 重新请求一个新的 Token
         * 2.Token 对应的 appKey 和工程里设置的 appKey 是否一致
         */
        @Override
        public void onTokenIncorrect()
        {
          if (callback != null)
            callback.onTokenIncorrect();
        }

        /**
         * 连接融云成功
         *
         * @param userid 当前 token 对应的用户 id
         */
        @Override
        public void onSuccess(String userid)
        {
          if (callback != null)
            callback.onSuccess(userid);
        }

        /**
         * 连接融云失败
         *
         * @param errorCode 错误码，可到官网 查看错误码对应的注释
         */
        @Override
        public void onError(RongIMClient.ErrorCode errorCode)
        {
          if (callback != null)
            callback.onError(errorCode);
        }
      });
    } else
      Log.e(TAG, "connect() error");
  }

  /**
   * 融云连接校验
   * <p>正式包需去掉</p>
   */
  public JvtdRongIM checkManifest()
  {
    try
    {
      RongPushClient.checkManifest(mContext);
    } catch (RongException e)
    {
      e.printStackTrace();
    }
    return this;
  }

  /**
   * <p>断开与融云服务器的连接。当调用此接口断开连接后，仍然可以接收 Push 消息。</p>
   * <p>若想断开连接后不接受 Push 消息，可以调用{@link #logout()}</p>
   */
  public void disconnect()
  {
    RongIM.getInstance().disconnect();
  }

  /**
   * <p>断开与融云服务器的连接，并且不再接收 Push 消息。</p>
   * <p>若想断开连接后仍然接受 Push 消息，可以调用 {@link #disconnect()}</p>
   */
  public void logout()
  {
    RongIM.getInstance().logout();
  }

  //------------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  功能自定义  ------------------------------------------------------
  //------------------------------------------------------------------------------------------------------------------------

  /**
   * 修改会话界面文字颜色
   */
  public JvtdRongIM registerMessageTemplate(BaseRongIMMessageItemProvider provider)
  {
    RongIM.registerMessageTemplate(provider);
    return this;
  }

  /**
   * 去除融云文件发送功能
   **/
  public JvtdRongIM removeFilePlugin()
  {
    List<IExtensionModule> moduleList = RongExtensionManager.getInstance().getExtensionModules();
    if (moduleList != null)
    {
      IExtensionModule module = null;
      for (IExtensionModule extensionModule : moduleList)
        if (extensionModule instanceof DefaultExtensionModule)
        {
          module = extensionModule;
          break;
        }
      RongExtensionManager.getInstance().unregisterExtensionModule(module);//注销之前的
      RongExtensionManager.getInstance().registerExtensionModule(new BaseExtensionModule());//注册新的
    }
    return this;
  }

  //-----------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  用户信息  ------------------------------------------------------
  //-----------------------------------------------------------------------------------------------------------------------

  /**
   * <p>设置用户信息的提供者，供 RongIM 调用获取用户名称和头像信息。</p>
   * <p>设置后，当 sdk 界面展示用户信息时，会回调 RongIM.UserInfoProvider.getUserInfo(String) 使用者只需要根据对应的 userId 提供对应的用户信息。</p>
   * <p>如果需要异步从服务器获取用户信息，使用者可以在此方法中发起异步请求，然后返回 null 信息。</p>
   * <p>在异步请求结果返回后，根据返回的结果调用 {@link #refreshUserInfoCache(UserInfo)} 刷新用户信息。</p>
   * <p>需在 {@link #init(String)} 后调用。</p>
   *
   * @param callback 调取接口回调
   */
  public JvtdRongIM setUserInfoProvider(RongIMUserInfoProviderCallback callback)
  {
    RongIM.setUserInfoProvider(userId ->
    {
      if (callback != null)
        // 异步请求服务器, 获取用户信息, 得到结果后, 需调用 refreshUserInfoCache(UserInfo) 刷新用户信息
        callback.getUserInfoByUserId(userId);
      return null;
    }, true);
    return this;
  }

  /**
   * <p>设置GroupUserInfo提供者，供RongIM 调用获取GroupUserInfo。</p>
   * <p>可以使用此方法，修改群组中用户昵称。</p>
   * <p>设置后，当 sdk 界面展示用户信息时，会回调 RongIM.GroupUserInfoProvider.getGroupUserInfo(String, String) 使用者只需要根据对应的 groupId, userId 提供对应的用户信息 GroupUserInfo。</p>
   * <p>如果需要异步从服务器获取用户信息，使用者可以在此方法中发起异步请求，然后返回 null 信息。</p>
   * <p>在异步请求结果返回后，根据返回的结果调用 {@link #refreshGroupUserInfoCache(GroupUserInfo)} 刷新信息。</p>
   * <p>需在 {@link #init(String)} 后调用。</p>
   *
   * @param callback 调取接口回调
   */
  public JvtdRongIM setGroupUserInfoProvider(RongIMGroupUserInfoProviderCallback callback)
  {
    RongIM.setGroupUserInfoProvider((groupId, userId) ->
    {
      if (callback != null)
        // 异步请求服务器, 获取用户信息, 得到结果后, 需调用 refreshGroupInfoCache(Group) 刷新用户信息
        callback.getGroupUserInfoByGroupUserId(groupId, userId);
      return null;
    }, true);
    return this;
  }

  /**
   * <p>设置群组信息的提供者。</p>
   * <p>设置后，当 sdk 界面展示群组信息时，会回调 RongIM.GroupInfoProvider.getGroupInfo(String) 使用者只需要根据对应的 groupId 提供对应的群组信息。</p>
   * <p>如果需要异步从服务器获取群组信息，使用者可以在此方法中发起异步请求，然后返回 null 信息。</p>
   * <p>在异步请求结果返回后，根据返回的结果调用 {@link #refreshGroupInfoCache(Group)} 刷新群组信息。</p>
   * <p>需在 {@link #init(String)} 后调用。</p>
   *
   * @param callback 调取接口回调
   */
  public JvtdRongIM setGroupInfoProvider(RongIMGroupInfoProviderCallback callback)
  {
    RongIM.setGroupInfoProvider(groupId ->
    {
      if (callback != null)
        // 异步请求服务器, 获取用户信息, 得到结果后, 需调用 refreshGroupInfoCache(Group) 刷新群组信息
        callback.getGroupInfoByGroupId(groupId);
      return null;
    }, true);
    return this;
  }

  /**
   * 刷新用户信息缓存
   */
  public void refreshUserInfoCache(UserInfo userInfo)
  {
    RongIM.getInstance().refreshUserInfoCache(userInfo);
  }

  /**
   * 刷新群组用户信息缓存
   */
  public void refreshGroupUserInfoCache(GroupUserInfo groupUserInfo)
  {
    RongIM.getInstance().refreshGroupUserInfoCache(groupUserInfo);
  }

  /**
   * 刷新群组信息缓存
   */
  public void refreshGroupInfoCache(Group group)
  {
    RongIM.getInstance().refreshGroupInfoCache(group);
  }

  //--------------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  事件监听  ------------------------------------------------------
  //--------------------------------------------------------------------------------------------------------------------------

  /**
   * 设置发送消息的监听。
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   * <p>注意：如果在 Activity 里设置，需要在 Activity 销毁时，将监听设置为 null，防止内存泄露。</p>
   *
   * @param listener 发送消息的监听。
   */
  public JvtdRongIM setSendMessageListener(BaseSendMessageListener listener)
  {
    RongIM.getInstance().setSendMessageListener(listener);
    return this;
  }

  /**
   * 设置接收消息的监听。
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   * <p>注意，建议设置在 Application 里面，这样才能在整个应用的生命周期，都能监听到接收消息事件。</p>
   *
   * @param listener 发送消息的监听。
   */
  public JvtdRongIM setOnReceiveMessageListener(BaseReceiveMessageListener listener)
  {
    RongIM.setOnReceiveMessageListener(listener);
    return this;
  }

  /**
   * 设置连接状态变化的监听器。
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   * <p>注意：建议设置在 Application 里面，这样才能在整个应用的生命周期，都能监听到状态变化。</p>
   *
   * @param listener 连接状态变化的监听器。
   */
  public JvtdRongIM setConnectionStatusListener(BaseConnectionStatusListener listener)
  {
    RongIM.setConnectionStatusListener(listener);
    return this;
  }

  /**
   * 设置会话列表操作监听
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   *
   * @param listener 会话列表操作监听器
   */
  public JvtdRongIM setConversationListBehaviorListener(BaseConversationListBehaviorListener listener)
  {
    RongIM.setConversationListBehaviorListener(listener);
    return this;
  }

  /**
   * 设置会话界面操作的监听器
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   *
   * @param listener 会话界面操作的监听器
   */
  public JvtdRongIM setConversationClickListener(BaseConversationClickListener listener)
  {
    RongIM.setConversationClickListener(listener);
    return this;
  }

  /**
   * 设置未读消息数变化监听器。
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   * <p>
   * 注意:如果是在 activity 中设置,那么要在 activity 销毁时,调用 {@link #removeUnReadMessageCountChangedObserver(IUnReadMessageObserver)}, 否则会造成内存泄漏。
   *
   * @param observer          接收未读消息消息的监听器。
   * @param conversationTypes 接收未读消息的会话类型。
   */
  public void addUnReadMessageCountChangedObserver(IUnReadMessageObserver observer, Conversation.ConversationType... conversationTypes)
  {
    RongIM.getInstance().addUnReadMessageCountChangedObserver(observer, conversationTypes);
  }

  /**
   * 注销已注册的未读消息数变化监听器。
   *
   * @param observer 接收未读消息消息的监听器。
   */
  public void removeUnReadMessageCountChangedObserver(IUnReadMessageObserver observer)
  {
    RongIM.getInstance().removeUnReadMessageCountChangedObserver(observer);
  }

  /**
   * 清除消息未读状态
   */
  public void clearMessagesUnreadStatus(Conversation.ConversationType conversationType, String targetId, RongIMClient.ResultCallback<Boolean> callback)
  {
    RongIM.getInstance().clearMessagesUnreadStatus(conversationType, targetId, callback);
  }

  /**
   * 根据会话类型的目标 Id,回调方式获取来自某用户（某会话）的未读消息数。
   */
  public void getUnreadCount(Conversation.ConversationType conversationType, String targetId, RongIMClient.ResultCallback<Integer> callback)
  {
    RongIM.getInstance().getUnreadCount(conversationType, targetId, callback);
  }

  /**
   * 清空某一会话的所有消息, 用于在删除好友或退出群组后调用
   */
  public void clearMessage(Conversation.ConversationType conversationType, String targetId, RongIMClient.ResultCallback<Boolean> callback)
  {
    RongIM.getInstance().clearMessages(conversationType, targetId, callback);
  }

  /**
   * 清空所有推送消息
   */
  public void clearAllPushNotifications()
  {
    // 清除所有的推送通知和后台消息通知。ex: A 账号离线或者退到后台，B 账号给 A 发送消息，A 设备会收到该消息的通知，调用此函数会清除该类型的通知。
    // 但是，如果是从开发者后台使用广播推送服务发送的推送通知，仍然会保留，不会清除
    RongPushClient.clearAllPushNotifications(mContext);
  }

  /**
   * 返回融云链接状态
   */
  public RongIMClient.ConnectionStatusListener.ConnectionStatus getCurrentConnectionStatus()
  {
    return RongIMClient.getInstance().getCurrentConnectionStatus();
  }

  //--------------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  基础会话功能  ------------------------------------------------------
  //--------------------------------------------------------------------------------------------------------------------------

  /**
   * 启动会话界面。
   *
   * <p>使用时，可以传入多种会话类型 {@link io.rong.imlib.model.Conversation.ConversationType} 对应不同的会话类型，开启不同的会话界面。
   * 如果传入的是 {@link io.rong.imlib.model.Conversation.ConversationType#CHATROOM}，sdk 会默认调用
   * {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)} 加入聊天室。
   * 如果你的逻辑是，只允许加入已存在的聊天室，请使用接口 {@link #startChatRoomChat(Context, String, boolean)} 并且第三个参数为 true</p>
   *
   * @param context          应用上下文。
   * @param conversationType 会话类型。
   * @param targetId         根据不同的 conversationType，可能是用户 Id、群组 Id 或聊天室 Id。
   * @param title            聊天的标题，开发者可以在聊天界面通过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。
   */
  public void startConversation(Context context, Conversation.ConversationType conversationType, String targetId, String title)
  {
    RongIM.getInstance().startConversation(context, conversationType, targetId, title);
  }

  /**
   * 启动会话列表界面。
   *
   * @param context               应用上下文。
   * @param supportedConversation 定义会话列表支持显示的会话类型，及对应的会话类型是否聚合显示。
   *                              例如：
   *                              Map<String, Boolean> map = new HashMap<>();
   *                              map.put(Conversation.ConversationType.PRIVATE.getName(), true); // 会话列表需要显示私聊会话, 第二个参数 true 代表私聊会话需要聚合显示
   *                              map.put(Conversation.ConversationType.GROUP.getName(), false);  // 会话列表需要显示群组会话, 第二个参数 false 代表群组会话不需要聚合显示
   */
  public void startConversationList(Context context, Map<String, Boolean> supportedConversation)
  {
    RongIM.getInstance().startConversationList(context, supportedConversation);
  }

  /**
   * 启动聚合后的某类型的会话列表。
   * <br> 例如：如果设置了单聊会话为聚合，则通过该方法可以打开包含所有的单聊会话的列表。
   *
   * @param context          应用上下文。
   * @param conversationType 会话类型。
   */
  public void startSubConversationList(Context context, Conversation.ConversationType conversationType)
  {
    RongIM.getInstance().startSubConversationList(context, conversationType);
  }

  /**
   * 启动单聊界面。
   *
   * @param context      应用上下文。
   * @param targetUserId 要与之聊天的用户 Id。
   * @param title        聊天的标题，开发者需要在聊天界面通过 intent.getData().getQueryParameter("title")获取该值, 再手动设置为聊天界面的标题。
   */
  public void startPrivateChat(Context context, String targetUserId, String title)
  {
    RongIM.getInstance().startPrivateChat(context, targetUserId, title);
  }

  // 注:
  // 聊天室拉取消息数设置：进入聊天室时默认拉取消息数为 10 条，根据需求可通过配置文件修改拉取消息条数，建议拉取消息数不超过 50 条，
  // 请在 res/values/rc_config.xml 文件中修改，为 -1 表示不获取任何历史消息，0 表示不特殊设置而使用 SDK 默认的设置（默认为获取10条），最大值为50。

  /**
   * 启动群组聊天界面。
   *
   * @param context       应用上下文。
   * @param targetGroupId 要聊天的群组 Id。
   * @param title         聊天的标题，开发者可以在聊天界面通过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。
   */
  public void startGroupChat(Context context, String targetGroupId, String title)
  {
    RongIM.getInstance().startGroupChat(context, targetGroupId, title);
  }

  /**
   * <p>启动聊天室会话。</p>
   * <p>设置参数 createIfNotExist 为 true，对应到 kit 中调用的接口是
   * {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)}.
   * 如果聊天室不存在，则自动创建并加入，如果回调失败，则弹出 warning。</p>
   * <p>设置参数 createIfNotExist 为 false，对应到 kit 中调用的接口是
   * {@link RongIMClient#joinExistChatRoom(String, int, RongIMClient.OperationCallback)}.
   * 如果聊天室不存在，则返回错误 {@link io.rong.imlib.RongIMClient.ErrorCode#RC_CHATROOM_NOT_EXIST}，并且会话界面会弹出 warning.
   * </p>
   *
   * @param context          应用上下文。
   * @param chatRoomId       聊天室 id。
   * @param createIfNotExist 如果聊天室不存在，是否创建。
   */
  public void startChatRoomChat(Context context, String chatRoomId, boolean createIfNotExist)
  {
    RongIM.getInstance().startChatRoomChat(context, chatRoomId, createIfNotExist);
  }

  /**
   * 加入聊天室。
   * <p>如果聊天室不存在，sdk 会创建聊天室并加入，如果已存在，则直接加入</p>
   * <p>加入聊天室时，可以选择拉取聊天室消息数目。</p>
   *
   * @param chatroomId      聊天室 Id。
   * @param defMessageCount 进入聊天室拉取消息数目，-1 时不拉取任何消息，0 时拉取 10 条消息，最多只能拉取 50 条。
   * @param callback        状态回调。
   */
  public void joinChatRoom(String chatroomId, int defMessageCount, RongIMClient.OperationCallback callback)
  {
    RongIM.getInstance().joinChatRoom(chatroomId, defMessageCount, callback);
  }

  /**
   * 加入已存在的聊天室。
   * <p>如果聊天室不存在，则加入失败</p>
   * <p>加入聊天室时，可以选择拉取聊天室消息数目。</p>
   *
   * @param chatroomId      聊天室 Id。
   * @param defMessageCount 进入聊天室拉取消息数目，-1 时不拉取任何消息，0 时拉取 10 条消息，最多只能拉取 50 条。
   * @param callback        状态回调。
   */
  public void joinExistChatRoom(String chatroomId, int defMessageCount, RongIMClient.OperationCallback callback)
  {
    RongIM.getInstance().joinExistChatRoom(chatroomId, defMessageCount, callback);
  }

  /**
   * 启动客户服聊天界面。
   */
  public void startCustomerServiceChat(Context context, String title, CSCustomServiceInfo customServiceInfo, String customerServiceId)
  {
    RongIM.getInstance().startCustomerServiceChat(context, customerServiceId, title, customServiceInfo);
  }

  /**
   * 搜索全部公众服务。
   *
   * @param keywords 搜索关键字。
   * @param callback 回调
   */
  public void searchPublicService(String keywords, RongIMClient.ResultCallback<PublicServiceProfileList> callback)
  {
    RongIM.getInstance().searchPublicService(RongIMClient.SearchType.EXACT, keywords, callback);
  }

  /**
   * 按公众服务类型搜索公众服务。
   *
   * @param keywords 搜索关键字。
   * @param callback 回调
   */
  public void searchPublicServicebyType(String keywords, RongIMClient.ResultCallback<PublicServiceProfileList> callback)
  {
    RongIM.getInstance().searchPublicServiceByType(Conversation.PublicServiceType.PUBLIC_SERVICE, RongIMClient.SearchType.EXACT, keywords, callback);
  }

  /**
   * 获取己关注公共账号列表
   *
   * @param callback 回调
   */
  public void getPublicServiceList(RongIMClient.ResultCallback<PublicServiceProfileList> callback)
  {
    RongIM.getInstance().getPublicServiceList(callback);
  }

  /**
   * 获取某公众号信息
   *
   * @param publicServiceId 公众号 Id。
   * @param callback        回调
   */
  public void getPublicServiceProfile(String publicServiceId, RongIMClient.ResultCallback<PublicServiceProfile> callback)
  {
    RongIM.getInstance().getPublicServiceProfile(Conversation.PublicServiceType.PUBLIC_SERVICE, publicServiceId, callback);
  }

  /**
   * 根据消息类型，targetId 保存某一会话的文字消息草稿。用于暂存用户输入但未发送的消息。
   *
   * @param conversationType 会话类型。
   * @param targetId         目标 Id。根据不同的 conversationType，可能是用户 Id、群组 Id 或聊天室 Id。
   * @param content          草稿的文字内容。
   * @param callback         是否保存成功的回调。
   */
  public void saveTextMessageDraft(Conversation.ConversationType conversationType, String targetId, String content, RongIMClient.ResultCallback<Boolean> callback)
  {
    RongIM.getInstance().saveTextMessageDraft(conversationType, targetId, content, callback);
  }

  /**
   * 根据消息类型，targetId 获取某一会话的文字消息草稿。用于获取用户输入但未发送的暂存消息。
   *
   * @param conversationType 会话类型。
   * @param targetId         目标 Id。根据不同的 conversationType，可能是用户 Id、群组 Id 或聊天室 Id。
   * @param callback         获取草稿文字内容的回调。
   */
  public void getTextMessageDraft(Conversation.ConversationType conversationType, String targetId, RongIMClient.ResultCallback<String> callback)
  {
    RongIM.getInstance().getTextMessageDraft(conversationType, targetId, callback);
  }

  /**
   * 根据消息类型，targetId 清除某一会话的文字消息草稿。
   *
   * @param conversationType 会话类型。
   * @param targetId         目标 Id。根据不同的 conversationType，可能是用户 Id、群组 Id 或聊天室 Id。
   * @param callback         获取草稿文字内容的回调。
   */
  public void clearTextMessageDraft(Conversation.ConversationType conversationType, String targetId, RongIMClient.ResultCallback<Boolean> callback)
  {
    RongIM.getInstance().clearTextMessageDraft(conversationType, targetId, callback);
  }

  //-----------------------------------------------------------------------------------------------------------------------
  //------------------------------------------------------  功能进阶  ------------------------------------------------------
  //-----------------------------------------------------------------------------------------------------------------------

  /**
   * 消息阅读回执
   * 通过 rc_config.xml 里的开关，开启消息的阅读回执功能。默认 false 为关闭状态，设置成 true 为开启。
   *
   * <p>需在 {@link #init(String)} 后调用。</p>
   * <p>目前只支持 PRIVATE、GROUP 和 DISCUSSION 三种类型。</p>
   *
   * @param types new Conversation.ConversationType[] {
   *              Conversation.ConversationType.PRIVATE,
   *              Conversation.ConversationType.GROUP,
   *              Conversation.ConversationType.DISCUSSION
   *              };
   */
  public void setReadReceiptConversationTypeList(Conversation.ConversationType[] types)
  {
    RongIM.getInstance().setReadReceiptConversationTypeList(types);
  }

  /**
   * 群组 ＠ 功能
   *
   * @ 功能默认为关闭状态，可以在 rc_config.xml 设置 rc_enable_mentioned_message 为 true 开启 @ 功能。
   * <p>
   * 设置 @ 成员信息提供者
   * <p>
   * 注, @ 所有人时需要新建一个 MentionedType 为 MentionedType.ALL的MentionedInfo ，并把它设置到 MessageContent中, 例
   * MentionedInfo mentionedInfo = new MentionedInfo(MentionedInfo.MentionedType.ALL, null, null);
   * textMessage.setMentionedInfo(mentionedInfo);
   * RongIM.getInstance().sendMessage(…);
   */
  public void setGroupMembersProvider(RongIM.IGroupMembersProvider groupMembersProvider)
  {
    RongIM.getInstance().setGroupMembersProvider(groupMembersProvider);
  }

  /**
   * 设置某一会话为置顶或者取消置顶，回调方式获取设置是否成功。
   *
   * @param type     会话类型。
   * @param id       目标 Id。根据不同的 conversationType，可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
   * @param isTop    是否置顶。
   * @param callback 设置置顶或取消置顶是否成功的回调。
   */
  public void setConversationToTop(Conversation.ConversationType type, String id, boolean isTop, RongIMClient.ResultCallback<Boolean> callback)
  {
    RongIM.getInstance().setConversationToTop(type, id, isTop, callback);
  }

  /**
   * 显示新消息提醒
   */
  public JvtdRongIM enableNewComingMessageIcon()
  {
    RongIM.getInstance().enableNewComingMessageIcon(true);
    return this;
  }

  /**
   * 显示未读消息数目
   */
  public JvtdRongIM enableUnreadMessageIcon()
  {
    RongIM.getInstance().enableUnreadMessageIcon(true);
    return this;
  }

  /**
   * 设置会话通知免打扰时间。
   *
   * @param startTime   起始时间 格式 HH:MM:SS。
   * @param spanMinutes 间隔分钟数大于 0 小于 1440。
   * @param callback    设置会话通知免打扰时间回调。
   */
  public JvtdRongIM setNotificationQuietHours(String startTime, int spanMinutes, RongIMClient.OperationCallback callback)
  {
    RongIM.getInstance().setNotificationQuietHours(startTime, spanMinutes, callback);
    return this;
  }

  /**
   * 移除会话通知免打扰时间。
   *
   * @param callback 移除会话通知免打扰时间回调。
   */
  public JvtdRongIM removeNotificationQuietHours(RongIMClient.OperationCallback callback)
  {
    RongIM.getInstance().removeNotificationQuietHours(callback);
    return this;
  }

  /**
   * 插入消息
   */
  public void insertOutgoingMessage(Conversation.ConversationType type, String targetId, Message.SentStatus sentStatus, MessageContent content, RongIMClient.ResultCallback<Message> callback)
  {
    RongIM.getInstance().insertOutgoingMessage(type, targetId, sentStatus, content, callback);
  }

  /**
   * 注册自定义消息类型
   */
  public JvtdRongIM registerMessageType(Class<? extends MessageContent> registerClass)
  {
    RongIM.registerMessageType(registerClass);
    return this;
  }

  /**
   * 注册自定义消息展示
   */
  public JvtdRongIM registerMessageTemplate(IContainerItemProvider.MessageProvider registerMessageTemplate)
  {
    RongIM.registerMessageTemplate(registerMessageTemplate);
    return this;
  }
}